﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using FTP;
using ImageResizer.FileExplorer.Interface;

namespace ImageResizer.FileExplorer.Implementations
{
    public class FtpFileExplorer : IFileExplorer
    {
        #region Private vars
        /// <summary>
        /// L'objet permettant d'effectur des opérations de type FTP
        /// </summary>
        private FTPclient _ftpClient; 
        #endregion

        #region CTOR

        /// <summary>
        /// Créer une nouvelle instance de FtpFileExplorer
        /// </summary>
        /// <param name="hostname">l'hôte FTP ciblé:  ftp://ftp.host.com ou ftp.host.com</param>
        public FtpFileExplorer(string hostname)
        {
            _ftpClient = new FTPclient(hostname);
        }

        /// <summary>
        /// Créer une nouvelle instance de FtpFileExplorer
        /// </summary>
        /// <param name="hostname">l'hôte FTP ciblé:  ftp://ftp.host.com ou ftp.host.com</param>
        /// <param name="username">l'identifiant nécessaire pour la connexion</param>
        /// <param name="password">le mot de passe nécessaire pour la connexion</param>
        public FtpFileExplorer(string hostname, string username, string password, string port, bool passiveMode)
        {
            _ftpClient = new FTPclient(hostname, username, password, port, passiveMode, true);
        } 

        #endregion

        /// <summary>
        /// Obtient la liste des fichiers contenus dans le repertoire
        /// </summary>
        /// <param name="rootDirectory">le répertoire à lister</param>
        /// <returns>la liste des fichiers</returns>
        public IEnumerable<string> DirectoryListFiles(string rootDirectory)
        {
            FTPdirectory v = _ftpClient.ListDirectoryDetail(rootDirectory);
            return v.GetFiles("").Select(pfileInfo => pfileInfo.Filename);
        }

        /// <summary>
        /// Obtient la liste des fichiers contenus dans le repertoire
        /// </summary>
        /// <param name="rootDirectory">le répertoire à lister</param>
        /// <param name="searchPattern">le pattern de recheche</param>
        /// <returns>la liste des fichiers</returns>
        public IEnumerable<string> DirectoryListFiles(string rootDirectory, string searchPattern)
        {
            Regex pattern = new Regex(searchPattern);
            return DirectoryListFiles(rootDirectory).Where(file => pattern.Match(file).Success);
        }

        /// <summary>
        ///  Obtient la liste des dossiers contenus dans le repertoire
        /// </summary>
        /// <param name="rootDirectory">le répertoire à lister</param>
        /// <returns>la liste des sous-dossiers</returns>
        public IEnumerable<string> DirectoryListSubDirs(string rootDirectory)
        {
            FTPdirectory v = _ftpClient.ListDirectoryDetail(rootDirectory);
            return v.GetDirectories().Select(pfileInfo => pfileInfo.NameOnly);
        }

        /// <summary>
        ///  Obtient la liste des dossiers contenus dans le repertoire
        /// </summary>
        /// <param name="rootDirectory">le répertoire à lister</param>
        /// <param name="searchPattern">le pattern de recherche</param>
        /// <returns>la liste des sous-dossiers</returns>
        public IEnumerable<string> DirectoryListSubDirs(string rootDirectory, string searchPattern)
        {
            Regex pattern = new Regex(searchPattern);
            return DirectoryListSubDirs(rootDirectory).Where(folder => pattern.Match(folder).Success);
        }

        /// <summary>
        /// Créé un dossier
        /// </summary>
        /// <param name="dirpath">le chemin à créer</param>
        /// <returns>le résultat de l'opération (true:ok, fasle:erreur)</returns>
        public bool DirectoryCreate(string dirpath)
        {
            return _ftpClient.FtpCreateDirectory(dirpath);
        }

        /// <summary>
        /// Supprime un dossier
        /// </summary>
        /// <param name="dirpath">le chemin à supprimer</param>
        /// <param name="recursively">si true efface le dossier ansi que son contenu (fichiers + subdirs), si false efface si vide</param>
        /// <returns>le résultat de l'opération (true:ok, fasle:erreur)</returns>
        public bool DirectoryDelete(string dirpath, bool recursively)
        {
            return _ftpClient.FtpDeleteDirectory(dirpath);
        }

        /// <summary>
        /// Indique si un répertoire existe
        /// </summary>
        /// <param name="dirpath">le répertoire à tester</param>
        /// <returns>true si le répertoire existe, false sinon</returns>
        public bool DirectoryExists(string dirpath)
        {
            try
            {
                var dir = FTPdirectory.GetParentDirectory(dirpath);
                return DirectoryListSubDirs(dir).Any(d => d == dirpath);
            }
            catch
            {
                return false;
            }

        }

        /// <summary>
        /// Supprime un fichier
        /// </summary>
        /// <param name="filepath">le chemin complet du fichier à supprimer</param>
        /// <returns>le résultat de l'opération (true:ok, fasle:erreur)</returns>
        public bool FileDelete(string filepath)
        {
            return _ftpClient.FtpDelete(filepath);
        }

        /// <summary>
        /// Indique si un fichier existe
        /// </summary>
        /// <param name="filepath">le fichier à tester</param>
        /// <returns>true si le fichier existe, false sinon</returns>
        public bool FileExists(string filepath)
        {
            return _ftpClient.FtpFileExists(filepath);
        }

        /// <summary>
        /// Télécharge un fichier
        /// </summary>
        /// <param name="source">la source à télécharger</param>
        /// <param name="destination">la destination</param>
        /// <param name="overwrite">indique si on écrase le fichier destination s'il existe déjà</param>
        /// <returns>le résultat de l'opération (true:ok, fasle:erreur)</returns>
        public bool FileDownload(string source, string destination, bool overwrite)
        {
            return _ftpClient.Download(source, destination, overwrite);
        }

        /// <summary>
        /// Envoi un fichier
        /// </summary>
        /// <param name="source">le chemin du fichier à envoyer</param>
        /// <param name="destination">la destination</param>
        /// <param name="overwrite">indique si on écrase le fichier destination s'il existe déjà</param>
        /// <returns>le résultat de l'opération (true:ok, fasle:erreur)</returns>
        public bool FileUpload(string source, string destination, bool overwrite)
        {
            return _ftpClient.Upload(source, destination);
        }

        /// <summary>
        /// Obtient le caractère de séparation des chemins
        /// </summary>
        public string PathSeparator
        {
            get { return "/"; }
        }
    }
}
